/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	CameraRenderPathSettingsFP.cpp
*
*	Comments	-	See CameraRenderPathSettingsFP.h
*
**************************************************************************************/
#include "../Include/CameraRenderPathSettingsFP.h"
#include "../Include/Engine.h"
#include "../Include/WindowView.h"
#include "../Include/GlobalGraphicsStrings.h"
#include "../Include/GraphicsResourceManager.h"
#include "../Include/ComponentCamera.h"
#include "../Include/Scene.h"
#include "../Include/ParameterBinderShaderResource.h"
#include "../Include/ParameterBinderScalar.h"

// Include render entries
#include "../Include/RenderEntryClearPipeline.h"
#include "../Include/RenderEntryList.h"
#include "../Include/RenderEntryModel.h"
#include "../Include/RenderEntryRenderTarget.h"
#include "../Include/RenderEntryViewport.h"
#include "../Include/RenderEntryClearRenderBuffers.h"
#include "../Include/RenderEntryPresent.h"
#include "../Include/RenderEntryDepthStencilState.h"
#include "../Include/RenderEntryBindParameters.h"
#include "../Include/RenderEntryLight.h"
#include "../Include/RenderEntryDispatchCompute.h"

namespace Pulse
{

	const UINT CameraRenderPathSettingsFP::m_tileSize = 16;
	const UINT CameraRenderPathSettingsFP::m_threadGroupSize = m_tileSize * m_tileSize;
	const UINT CameraRenderPathSettingsFP::m_threadGroupMaxLights = 256;

	CameraRenderPathSettingsFP::CameraRenderPathSettingsFP( ComponentCamera *pCamera )
	{
		m_pCameraOwner = pCamera;

		m_pBufferLights = PSX_NULL;
		m_pBufferLightIndices = PSX_NULL;

		m_pREDispatchCompute = PSX_NULL;

		m_pDepthBuffer = PSX_NULL;
		m_pCompositeBuffer = PSX_NULL;

		m_pDSState2n3 = PSX_NULL;

		m_pREViewport = PSX_NULL;

		m_pRERenderTarget1 = PSX_NULL;
		m_pREDepthStencil1 = PSX_NULL;
		m_pREClearPipeline1 = PSX_NULL;

		m_pREBindParams2 = PSX_NULL;
		m_pREClearPipeline2 = PSX_NULL;

		m_pRERenderTarget3 = PSX_NULL;
		m_pREDepthStencil3 = PSX_NULL;
		m_pREBindParams3 = PSX_NULL;
		m_pREClearPipeline3 = PSX_NULL;

		m_pREPresent = PSX_NULL;
	}

	CameraRenderPathSettingsFP::~CameraRenderPathSettingsFP( void )
	{
		Cleanup();
	}

	void CameraRenderPathSettingsFP::OnRender( RenderView *pView )
	{
		// NOTE: Might move this to camera specific
		pView->AddRenderEntry( m_pREViewport );

		// Z-Prepass
		pView->AddRenderEntry( m_pRERenderTarget1 );
		//pView->AddRenderEntry( m_pREDepthStencil1 ); // transfered to technique
		pView->AddRenderEntry( m_pREClearPipeline1 );

		// Lighting
		pView->AddRenderEntry( m_pREBindParams2 );
		pView->AddRenderEntry( m_pREDispatchCompute );
		pView->AddRenderEntry( m_pREClearPipeline2 );

		/*
		pView->AddRenderEntry( m_pRERenderTarget2 );
		pView->AddRenderEntry( m_pREDepthStencil2 ); // transfered to technique
		*/

		// Forward rendering
		pView->AddRenderEntry( m_pRERenderTarget3 );
		//pView->AddRenderEntry( m_pREDepthStencil3 ); // transfered to technique
		pView->AddRenderEntry( m_pREBindParams3 );
		pView->AddRenderEntry( m_pREClearPipeline3 );

		//pView->AddRenderEntry( m_pREPresent );
	}

	EErrorCode::Type CameraRenderPathSettingsFP::UpdateBufferSizes( void )
	{
		Engine *pEngine = Engine::GetInstance();
		Renderer *pRenderer = pEngine->GetRenderer();
		RenderPathForwardPlus *pRenderPath = pRenderer->GetRenderPath();
		ParameterSystem *pParamSys = pRenderer->GetParameterSystem();
		GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();

		WindowView *pWindowView = m_pCameraOwner->GetOwnerUnsafe()->GetScene()->GetWindowViewOwner();
		const SIZE_T viewWidth = pWindowView->GetWidth();
		const SIZE_T viewHeight = pWindowView->GetHeight();
		const SIZE_T textureWidth = pWindowView->GetWidth();
		const SIZE_T textureHeight = pWindowView->GetHeight();
		const UINT numLightsPerTile = pRenderPath->GetNumLightsPerTile();
		const UINT numTilesX = ComputeNumThreadGroups( m_tileSize, viewWidth );
		const UINT numTilesY= ComputeNumThreadGroups( m_tileSize, viewHeight );

		// For safety, release buffers
		ReleaseBuffers();

		// Error check if we should re-create resources
		if ( viewWidth == 0 || viewHeight == 0 )
		{
			return EErrorCode::_ERROR;
		}

		// Recreate buffers
		// Create buffers
		////////////////////

		// Create depth buffer with shader resource and depth buffer binding views
		Texture2DDesc depthBufferTexDesc;
		depthBufferTexDesc.SetAsDepthBuffer( (UINT)textureWidth, (UINT)textureHeight, 
			EGraphicsFormat::R24G8_TYPELESS, TRUE );

		DepthStencilViewDesc dsvDesc;
		Tex2DInfoDSV tex2DInfoDSV;
		tex2DInfoDSV.mipSlice = 0;
		dsvDesc.Set( EGraphicsFormat::D24_UNORM_S8_UINT, EGraphicsDSVDimension::TEXTURE2D, EDSVReadOnlyFlag::NONE, &tex2DInfoDSV );
		depthBufferTexDesc.SetDepthStencilView( &dsvDesc );

		ShaderResourceViewDesc srvDesc;
		Tex2DInfoSRV tex2DInfoSRV;
		tex2DInfoSRV.mipLevels = 1;
		tex2DInfoSRV.mostDetailedMip = 0;
		srvDesc.Set( EGraphicsFormat::R24_UNORM_X8_TYPELESS, EGraphicsSRVDimension::TEXTURE2D, &tex2DInfoSRV );
		depthBufferTexDesc.SetShaderResourceView( &srvDesc );

		m_pDepthBuffer = pGM->CreateTexture2D( &depthBufferTexDesc );

		if ( m_pDepthBuffer == PSX_NULL )
		{
			PSX_PushError( "Failed to create Light Pre-Pass depth buffer." );
			return EErrorCode::GRAPHICS;
		}

		
		{
			// Create light buffer
			{
				StructuredBufferDesc desc;

				desc.Set( sizeof(ShaderLight), pRenderPath->GetNumLightsPerTile(), EBufferUsage::DYNAMIC );
				m_pBufferLights = pGM->CreateStructuredBuffer( GFX_FP_PARAM_LIGHTS, &desc );

				if ( m_pBufferLights == PSX_NULL )
				{
					PSX_PushError( "Failed to create light buffer for the forward plus renderer." );
					ReleaseBuffers();
					return EErrorCode::_ERROR;
				}
			}

			// Create light indices buffer
			{
				BufferDesc desc;
				const UINT numElements = numLightsPerTile * numTilesX * numTilesY;

				desc.Set( EGraphicsFormat::R8_UINT, numElements, EBufferUsage::DEFAULT );

				m_pBufferLightIndices = pGM->CreateBuffer( GFX_FP_PARAM_LIGHT_INDICES_OUT, &desc );

				if ( m_pBufferLights == PSX_NULL )
				{
					PSX_PushError( "Failed to create light buffer for the forward plus renderer." );
					ReleaseBuffers();
					return EErrorCode::_ERROR;
				}
			}

			//  Set render entry compute
			{
				// Set the thread count for the dispatch call and its params including the number of lights params
				{
					m_pREDispatchCompute->SetThreadCounts( numTilesX, numTilesY, 1 );

					// Update number of tiles Params
					{
						ParameterScalar *pParam ;
						ParameterBinderScalar *pBinder;

						// Number of tiles X
						pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_X );
						pBinder = (ParameterBinderScalar*)m_pREDispatchCompute->m_parameters.GetParameterBinder( pParam );
						pBinder->SetAsScalar( numTilesX );

						// Number of tiles Y
						pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_Y );
						pBinder = (ParameterBinderScalar*)m_pREDispatchCompute->m_parameters.GetParameterBinder( pParam );
						pBinder->SetAsScalar( numTilesY );

						//// Number of lights - Already done in initialize
						//pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_LIGHTS );
						//pBinder = (ParameterBinderScalar*)m_pREDispatchCompute->m_parameters.GetParameterBinder( pParam );
						//pBinder->SetAsScalar( 0 );
						//m_pNumLights = pBinder; // Cache this binder since we'll be setting the value every frame
					}
				}
			}

			// Set params for geometry stage
			{
				// Update number of tiles Params
				{
					ParameterScalar *pParam ;
					ParameterBinderScalar *pBinder;

					// Number of tiles X
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_X );
					pBinder = (ParameterBinderScalar*)m_pREBindParams3->FindParameterBinder( pParam );
					pBinder->SetAsScalar( numTilesX );

					// Number of tiles Y
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_Y );
					pBinder = (ParameterBinderScalar*)m_pREBindParams3->FindParameterBinder( pParam );
					pBinder->SetAsScalar( numTilesY );
				}
			}
		}

		// Create composit buffer
		// The default is WindowView's render texture
		//Texture2DDesc compositeBufferTexDesc;
		//compositeBufferTexDesc.Set( ETextureUsage::NORMAL, EGraphicsFormat::R8G8B8A8_UNORM,
		//	textureWidth, textureHeight );
		//m_pCompositeBuffer = pGM->CreateTexture2D( &compositeBufferTexDesc );
		// TODO: If this is not the active camera, create our own composite texture...
		m_pCompositeBuffer = pWindowView->GetRenderTexture();
		if ( m_pCompositeBuffer == PSX_NULL )
		{
			PSX_PushError( "Failed to create Light Pre-Pass composite buffer" );
			return EErrorCode::GRAPHICS;
		}

		BindBuffers( m_pDepthBuffer, m_pBufferLights, m_pBufferLightIndices, m_pCompositeBuffer );

		// Last step update viewport
		{
			Viewport viewport( 0.0f, 0.0f, (FLOAT)textureWidth, (FLOAT)textureHeight );		
			m_pREViewport->SetViewport( &viewport );
		}

		return EErrorCode::OKAY;
	}

	Texture2D * CameraRenderPathSettingsFP::GetCompositeTexture( void )
	{
		if ( m_pCompositeBuffer )
		{
			m_pCompositeBuffer->AddRef();
			return m_pCompositeBuffer;
		}

		return PSX_NULL;
	}

	EErrorCode::Type CameraRenderPathSettingsFP::Initialize( void )
	{
		if ( m_pRERenderTarget1 != PSX_NULL )
		{
			// Already initialized.
			return EErrorCode::OKAY;
		}

		Engine					*pEngine = Engine::GetInstance();
		Renderer				*pRenderer = pEngine->GetRenderer();
		RenderPathForwardPlus	*pRenderPath = pRenderer->GetRenderPath();
		ParameterSystem			*pParamSys = pRenderer->GetParameterSystem();
		GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();

		m_pREDispatchCompute = new RenderEntryDispatchCompute;

		// Only create the render entries first
		m_pREViewport = new RenderEntryViewport;

		m_pRERenderTarget1 = new RenderEntryRenderTarget;
		m_pREDepthStencil1 = new RenderEntryDepthStencilState;
		m_pREClearPipeline1 = new RenderEntryClearPipeline( TRUE, TRUE, TRUE, TRUE, TRUE, FALSE );

		m_pREBindParams2 = new RenderEntryBindParameters;
		m_pREClearPipeline2 = new RenderEntryClearPipeline( TRUE, TRUE, TRUE, TRUE, TRUE, TRUE );

		m_pRERenderTarget3 = new RenderEntryRenderTarget;
		m_pREDepthStencil3 = new RenderEntryDepthStencilState;
		m_pREBindParams3 = new RenderEntryBindParameters;
		m_pREClearPipeline3 = new RenderEntryClearPipeline( TRUE, TRUE, TRUE, TRUE, TRUE, FALSE );

		m_pREPresent = new RenderEntryPresent;

		if ( m_pRERenderTarget1 == PSX_NULL || m_pREDepthStencil1 ==PSX_NULL ||
			m_pREBindParams2 == PSX_NULL || m_pRERenderTarget3 == PSX_NULL || 
			m_pREDepthStencil3 == PSX_NULL || m_pREBindParams3 == PSX_NULL || 
			m_pREPresent == PSX_NULL )
		{
			PSX_PushError( "Out of memory. Failed to initialize render entries." );
			return EErrorCode::MEMORY;
		}

		// ? Pass
		{
			m_pREViewport->SetStage( ERenderViewStage::MAIN );
			m_pREViewport->SetStageStep( ERenderViewStageStep::PRE_PROCESS );
			// viewport( 0.0f, 0.0f, (FLOAT)m_pWindowViewOwner->GetWidth(), (FLOAT)m_pWindowViewOwner->GetHeight() );		
			//m_pREViewport->SetViewport( &viewport );
		}

		// Stage 1 - Z-Prepass
		{
			m_pRERenderTarget1->SetStage( ERenderViewStage::GBUFFER );
			m_pRERenderTarget1->SetStageStep( ERenderViewStageStep::PRE_PROCESS );
			m_pRERenderTarget1->SetClearBuffers( TRUE );
			//m_pRERenderTarget1->SetDepthStencilBuffer( m_pDepthBuffer );
			//m_pRERenderTarget1->SetRenderTarget( 0, m_pNormalBuffer );

			m_pREDepthStencil1->SetStage( ERenderViewStage::GBUFFER );
			m_pREDepthStencil1->SetStageStep( ERenderViewStageStep::PRE_PROCESS );
			m_pREDepthStencil1->SetDepthStencilState( PSX_NULL ); // default depth stencil state

			m_pREClearPipeline1->SetStage( ERenderViewStage::GBUFFER );
			m_pREClearPipeline1->SetStageStep( ERenderViewStageStep::POST_PROCESS );
		}

		// Stage 2 - Lighting Pass
		{	
			m_pREBindParams2->SetStage( ERenderViewStage::LIGHTING );
			m_pREBindParams2->SetStageStep( ERenderViewStageStep::PRE_PROCESS );

			m_pREDispatchCompute->SetStage( ERenderViewStage::LIGHTING );
			m_pREDispatchCompute->SetStageStep( ERenderViewStageStep::PROCESS );
			
			// Add binders
			{
				// Add lights buffer parameter 
				{
					ParameterShaderResource *pParam = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHTS, EShaderResource::STRUCTURED_BUFFER );
					m_pREDispatchCompute->m_parameters.AddParameterBinder( pParam );
				}

				// Add light indices buffer parameter
				{
					ParameterShaderResource *pParam = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHT_INDICES_OUT, EShaderResource::UNORDERED_ACCESS );
					m_pREDispatchCompute->m_parameters.AddParameterBinder( pParam );
				}

				// Params
				{
					ParameterScalar *pParam ;
					ParameterBinderScalar *pBinder;

					// Number of tiles X
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_X );
					m_pREDispatchCompute->m_parameters.AddParameterBinder( pParam );

					// Number of tiles Y
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_Y );
					m_pREDispatchCompute->m_parameters.AddParameterBinder( pParam );

					// Number of lights
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_LIGHTS );
					pBinder = (ParameterBinderScalar*)m_pREDispatchCompute->m_parameters.AddParameterBinder( pParam );
					pBinder->SetAsScalar( 0 );
					m_pNumLights2 = pBinder; // Cache this binder since we'll be setting the value every frame
				}

				// Set render pass
				{
					Effect *pEffect = pGM->FindEffect( GFX_FP_EFFECT );
					RenderTechnique *pTechnique = pEffect->GetTechnique();

					PSX_Assert( pTechnique->GetNumRenderPasses() == 1, "Currently this technique has only one render pass." );

					m_pREDispatchCompute->m_pRenderPass = pTechnique->GetRenderPass( 0 );

					pTechnique->Release();
					pEffect->Release();
				}
			}

			m_pREClearPipeline2->SetStage( ERenderViewStage::LIGHTING );
			m_pREClearPipeline2->SetStageStep( ERenderViewStageStep::POST_PROCESS );
		}

		// Stage 3 - Composite Pass
		{
			m_pRERenderTarget3->SetStage( ERenderViewStage::COMPOSITE );
			m_pRERenderTarget3->SetStageStep( ERenderViewStageStep::PRE_PROCESS );
			m_pRERenderTarget3->SetClearBuffers( TRUE );
			//m_pRERenderTarget3->SetRenderTarget( 0, m_pCompositeBuffer );

			m_pREDepthStencil3->SetStage( ERenderViewStage::COMPOSITE );
			m_pREDepthStencil3->SetStageStep( ERenderViewStageStep::PRE_PROCESS );
			m_pREDepthStencil3->SetDepthStencilState( m_pDSState2n3 );

			m_pREBindParams3->SetStage( ERenderViewStage::COMPOSITE );
			m_pREBindParams3->SetStageStep( ERenderViewStageStep::PRE_PROCESS );

			// Set and add binders for stage 3
			{
				ParameterShaderResource *pShaderRes;
				IParameterBinder *pParamBinder;

				pShaderRes = pParamSys->GetShaderResource( GFX_LP_LIGHT_BUFFER, EShaderResource::TEXTURE2D );
				pParamBinder = m_pREBindParams3->AddParameter( pShaderRes );
				//pParamBinder->SetAsShaderResource( m_pLightBuffer );

				pShaderRes = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHTS, EShaderResource::STRUCTURED_BUFFER );
				m_pREBindParams3->AddParameter( pShaderRes );


				pShaderRes = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHT_INDICES, EShaderResource::BUFFER );
				m_pREBindParams3->AddParameter( pShaderRes );

				// Number of lights
				{
					ParameterScalar *pParam;
					ParameterBinderScalar *pBinder;

					// Number of tiles X
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_X );
					m_pREBindParams3->AddParameter( pParam );

					// Number of tiles Y
					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_TILE_Y );
					m_pREBindParams3->AddParameter( pParam );

					pParam = pParamSys->GetScalar( GFX_FP_PARAM_NUM_LIGHTS );
					pBinder = (ParameterBinderScalar*)m_pREBindParams3->AddParameter( pParam );
					pBinder->SetAsScalar( 0 );
					m_pNumLights3 = pBinder; // Cache this binder since we'll be setting the value every frame
				}
			}

			m_pREClearPipeline3->SetStage( ERenderViewStage::COMPOSITE );
			m_pREClearPipeline3->SetStageStep( ERenderViewStageStep::POST_PROCESS );
		}

		// TODO: Middle pass to transfer composite to final buffer.
		//	A separate system should probably be created to handle this task.

		// HACK: Present
		m_pREPresent->SetStage( ERenderViewStage::POST_PROCESS );

		return EErrorCode::OKAY;
	}

	void CameraRenderPathSettingsFP::Cleanup( void )
	{
		ReleaseBuffers();

		PSX_SafeRelease( m_pDSState2n3 );

		PSX_SafeDelete( m_pREViewport );
		//
		PSX_SafeDelete( m_pRERenderTarget1 );
		PSX_SafeDelete( m_pREDepthStencil1 );
		PSX_SafeDelete( m_pREClearPipeline1 );

		PSX_SafeDelete( m_pREBindParams2 );
		PSX_SafeDelete( m_pREDispatchCompute );
		PSX_SafeDelete( m_pREClearPipeline2 );

		PSX_SafeDelete( m_pRERenderTarget3 );
		PSX_SafeDelete( m_pREDepthStencil3 );
		PSX_SafeDelete( m_pREBindParams3 );
		PSX_SafeDelete( m_pREClearPipeline3 );

		PSX_SafeDelete( m_pREPresent );
	}

	void CameraRenderPathSettingsFP::ReleaseBuffers( void )
	{
		Engine *pEngine = Engine::GetInstance();
		Renderer *pRenderer = pEngine->GetRenderer();
		ParameterSystem *pParamSys = pRenderer->GetParameterSystem();

		// Before releasing, remove references first
		BindBuffers( PSX_NULL, PSX_NULL, PSX_NULL, PSX_NULL );

		// TODO: References in the graphics pipeline

		// Now release
		PSX_SafeRelease( m_pBufferLights );
		PSX_SafeRelease( m_pBufferLightIndices );

		PSX_SafeRelease( m_pDepthBuffer );
		PSX_SafeRelease( m_pCompositeBuffer );
	}

	void CameraRenderPathSettingsFP::BindBuffers( Texture2D *pDepthBuffer,  StructuredBuffer *pLightsBuffer, Buffer *pLightIndices, Texture2D *pCompositeBuffer )
	{
		Engine *pEngine = Engine::GetInstance();
		Renderer *pRenderer = pEngine->GetRenderer();
		ParameterSystem *pParamSys = pRenderer->GetParameterSystem();

		// Before releasing, remove references first

		// References in the render entries
		// Stage 1 - Geometry Pass
		{
			m_pRERenderTarget1->SetDepthStencilBuffer( pDepthBuffer );
		}

		// Remains from the old lightprepass
		// Stage 2 - Lighting Pass
		{	
			// Set and add binders
			{
				// Add lights buffer parameter 
				{
					ParameterShaderResource *pParam = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHTS, EShaderResource::STRUCTURED_BUFFER );
					ParameterBinderShaderResource *pBinder = (ParameterBinderShaderResource *)m_pREDispatchCompute->m_parameters.GetParameterBinder( pParam );

					if ( pBinder )
					{
						pBinder->SetAsShaderResource( pLightsBuffer );
					}
					else
					{
						PSX_PushWarning( "Light buffer shader resource not yet created." );
					}
				}

				// Add light indices buffer parameter
				{
					ParameterShaderResource *pParam = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHT_INDICES_OUT, EShaderResource::UNORDERED_ACCESS );
					ParameterBinderShaderResource *pBinder = (ParameterBinderShaderResource *)m_pREDispatchCompute->m_parameters.GetParameterBinder( pParam );

					if ( pBinder )
					{
						pBinder->SetAsShaderResource( pLightIndices );
					}
					else
					{
						PSX_PushWarning( "Light Indicies shader buffer resource not yet created." );
					}
				}
			}
		}

		// Stage 3 - Composite Pass
		{
			m_pRERenderTarget3->SetDepthStencilBuffer( pDepthBuffer );
			m_pRERenderTarget3->SetRenderTarget( 0, pCompositeBuffer );

			// Set and add binders for stage 3
			{
				{
					ParameterShaderResource *pShaderRes;
					ParameterBinderShaderResource *pBinder;

					pShaderRes = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHTS, EShaderResource::STRUCTURED_BUFFER );
					pBinder = (ParameterBinderShaderResource*)m_pREBindParams3->FindParameterBinder( pShaderRes );

					pBinder->SetAsShaderResource( pLightsBuffer );
				}


				{
					ParameterShaderResource *pShaderRes;
					ParameterBinderShaderResource *pBinder;

					pShaderRes = pParamSys->GetShaderResource( GFX_FP_PARAM_LIGHT_INDICES, EShaderResource::BUFFER );
					pBinder = (ParameterBinderShaderResource*)m_pREBindParams3->FindParameterBinder( pShaderRes );

					pBinder->SetAsShaderResource( pLightIndices );
				}
			}
		}
	}

	const UINT CameraRenderPathSettingsFP::ComputeNumThreadGroups( const UINT threadGroupSize, const UINT numElements ) const
	{
		UINT numThreads = numElements / threadGroupSize;

		numThreads += (numElements % threadGroupSize) > 0 ? 1 : 0;
		return numThreads;
	}

	void CameraRenderPathSettingsFP::OnPreRenderViewExecute( RenderView *pView )
	{
		GraphicsPipeline *pPipeline = Engine::GetInstance()->GetRenderer()->GetPipeline();
		ComponentCamera *pCamera = pView->GetCamera();
		LightManager *pLights = pView->GetLightManager();

		// Process lights first
		if ( pCamera )
		{
			SIZE_T numLights = pLights->GetNumLights();
			
			if ( numLights )
			{

				MappedResource mapRes;
				m_pBufferLights->Map( &mapRes );
				ShaderLight *pShaderLight = (ShaderLight*)mapRes.pData;

				if ( pShaderLight )
				{
					for ( SIZE_T i = 0; i < numLights; ++i )
					{
						const ComponentLight *pLight = pLights->GetLight( i );

						PSX_MemCopy( pShaderLight[i].position, pLight->GetOwnerUnsafe()->GetTransformWorld()->GetTranslation().v, sizeof(pShaderLight[i].position) );
						PSX_MemCopy( pShaderLight[i].color, pLight->GetColor()->v, sizeof(pShaderLight[i].color) );
						pShaderLight[i].range = pLight->GetRange();
					}
				}
				else
				{
					PSX_PushError( "Can't map lights buffer." );
				}

				m_pBufferLights->UnMap();
				pLights->ClearLights();

				if ( m_pNumLights2 && m_pNumLights3 )
				{
					m_pNumLights2->SetAsScalar( (UINT)numLights );
					m_pNumLights3->SetAsScalar( (UINT)numLights );
				}
				else
				{
					PSX_PushError( "Num lights parameter binder does not exist." );
				}
			}
		}
	}

}